using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Threading;
using System.Net;
using System.Collections;
using System.Collections.Specialized;
using System.Windows.Forms;//TODO: temp.

namespace DotNetGear.WindowsMedia
{
    class StreamDownloader : IDisposable 
    {
        private Thread _thread;
        private static readonly Guid _headerObject = new Guid("75B22630-668E-11CF-A6D9-00AA0062CE6C");
        private static readonly Guid _dataObject = new Guid("75B22636-668E-11CF-A6D9-00AA0062CE6C");
        private string _status;
        private bool _disposed;
        private UInt64 _bytes;
        private string _url;
        private string _filename;
        private string _path;
        private UInt64 _length;
        public event EventHandler StatusChanged;

        public string Status
        {
            get
            {
                return _status;
            }
        }

        public UInt64 BytesDownloaded
        {
            get
            {
                return _bytes;
            }
        }

        public bool IsWorking
        {
            get
            {
                return _thread.IsAlive;
            }
        }

        public UInt64 Length
        {
            get
            {
                return _length;
            }
        }

        public string Name
        {
            get
            {
                return _filename;
            }
        }
        
        public StreamDownloader(string url, string path, string name)
        {
            _url = url;
            if (_url.Substring(0, 4) == "mms:")
            {
                _url = _url.Replace("mms:", "http:");
            }
            _filename = name;
            _path = path;
            _length = 0;
            if (!Directory.Exists(_path)) Directory.CreateDirectory(_path);
            _thread = new Thread(new ThreadStart(Work));
            _thread.Priority = ThreadPriority.BelowNormal;
            _thread.Start();
        }

        private void Work()
        {
            try
            {
                _status = "Connecting";
                StatusChanged.BeginInvoke(this, new EventArgs(), null, null);
                _disposed = false; _bytes = 0;
                int entry1 = 0, entry2 = 0, count = 0;
                {

                    HttpWebRequest req = (HttpWebRequest)WebRequest.Create(_url);

                    WebHeaderCollection whr = new WebHeaderCollection();
                    whr.Add("Pragma", @"no-cache,rate=1.000000,stream-time=0,stream-offset=0:0,request-context=1,max-duration=0,xClientGUID={2200AD50-2C39-46c0-AE0A-2CA76D8C766D}");
                    req.Headers = whr;

                    req.Accept = @"*/*";
                    req.UserAgent = @"NSPlayer/4.1.0.3925";
                    req.Method = "GET";

                    HttpWebResponse res = (HttpWebResponse)req.GetResponse();
                    Stream s = res.GetResponseStream();

                    //HTTP.Header h = new HTTP.Header(s);
                    byte[] buff = new byte[12]; // Reads HTTP header.
                    s.Read(buff, 0, buff.Length);
                    int rv = 0;
                    while (rv != -1)
                    {
                        rv = s.ReadByte();
                        if (_disposed) return;
                    }

                }
                ArrayList fnames = new ArrayList();
                _status = "Downloading";
                StatusChanged.BeginInvoke(this, new EventArgs(), null, null);
                {

                    HttpWebRequest req = (HttpWebRequest)WebRequest.Create(_url);

                    WebHeaderCollection whr = new WebHeaderCollection();
                    whr.Add("Pragma", @"Pragma: no-cache,rate=1.000000,request-context=2,xPlayStrm=1,xClientGUID={2200AD50-2C39-46c0-AE0A-2CA76D8C766D},stream-switch-count=" + count + ",stream-switch-entry=ffff:" + entry1 + ":0 ffff:" + entry2 + ":0");
                    req.Headers = whr;

                    req.Accept = @"*/*";
                    req.UserAgent = @"NSPlayer/4.1.0.3925";
                    req.Method = "GET";

                    HttpWebResponse res = (HttpWebResponse)req.GetResponse();
                    Stream s = res.GetResponseStream();
                    FileStream fs = null;
                    byte[] guid = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };

                    try
                    {
                        int ec = 0;
                        while (!_disposed)
                        {
                            Thread.Sleep(0);
                            Array.Copy(guid, 1, guid, 0, 15);
                            int rb = s.ReadByte();
                            if (rb == -1) break;
                            guid[15] = (byte)rb;
                            if (fs != null) fs.WriteByte((byte)rb);
                            if (new Guid(guid) == _headerObject)
                            {
                                if (fs != null) fs.Close();
                                string fn = Guid.NewGuid().ToString("N") + ".asf";
                                string fname = _path + "\\" + fn;
                                fnames.Add(fn);
                                fs = new FileStream(fname, FileMode.Create);
                                fs.Write(guid, 0, guid.Length);
                            }
                            if (new Guid(guid) == _dataObject)
                            {
                                byte[] len = new byte[8];
                                for (int i = 0; i < len.Length; i++)
                                {
                                    len[i] = (byte)s.ReadByte();
                                    fs.WriteByte(len[i]);
                                    _length = BitConverter.ToUInt64(len, 0);
                                }
                            }
                            _bytes++;
                            ec++; if (ec == 1024)
                            {
                                ec = 0;
                                StatusChanged.BeginInvoke(this, new EventArgs(), null, null);
                            }
                        }
                        if (fs != null) fs.Close();
                    }
                    catch (TimeoutException ex)
                    {
                        //Do nothing.
                        _status = "Done ?" + ex.Message;
                    }
                    catch (Exception ex)
                    {
                        _status = ex.Message;
                    }
                }

                _status = "Making indexes";
                //TODO: Eleminate using this external indexer.
                string oname = "-o \"" + _filename + ".wmv\" ";
                string inames = " ";
                foreach (string iname in fnames)
                {
                    inames += "-i \"" + iname + "\" ";
                }
                StatusChanged.BeginInvoke(this, new EventArgs(), null, null);
                System.Diagnostics.Process p = new System.Diagnostics.Process();
                p.StartInfo.FileName = Application.StartupPath + "\\asfbin.exe";
                p.StartInfo.WorkingDirectory = _path;
                p.StartInfo.Arguments = inames + oname + "-sionly -y -q";
                p.StartInfo.UseShellExecute = false;
                p.StartInfo.CreateNoWindow = true;
                p.StartInfo.RedirectStandardOutput = true;
                p.Start(); StreamReader sr = p.StandardOutput;
                p.WaitForExit();
                if (p.ExitCode != 0)
                {
                    _status = "Error during indexing. ExitCode = " + p.ExitCode + "\n\r" + sr.ReadToEnd();
                    System.Diagnostics.Debug.Write(_status);
                    return;
                }

                foreach (string iname in fnames)
                {
                    File.Delete(iname);
                }

                _status = "Done!";
                StatusChanged.BeginInvoke(this, new EventArgs(), null, null);
            }
            catch (Exception ex)
            {
                _status = ex.Message;
            }
            finally
            {
                //TODO:?
            }
        }

        #region Dispose

        public void Dispose()
        {
            _disposed = true;
            if(!_thread.Join(5000))
            {
                _thread.Abort();//Comment this when debugging.
                System.Diagnostics.Debug.WriteLine("StreamDownloder thread still working.");
            }
        }

        ~StreamDownloader()
        {
            Dispose();
            
        }

        #endregion
    }

}
